package com.yimils.core.sys.shiro;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yimils.core.sys.beanUtils.RoleVoBeanUtils;
import com.yimils.core.sys.beanUtils.UserResourceUtil;
import com.yimils.core.sys.beanUtils.UserRoleVoBeanUtils;
import com.yimils.core.sys.entity.*;
import com.yimils.core.sys.mapper.ResourceMapper;
import com.yimils.core.sys.mapper.RoleMapper;
import com.yimils.core.sys.mapper.RoleResourceMapper;
import com.yimils.core.sys.po.RoleResourceDo;
import com.yimils.core.sys.po.UserMenuDo;
import com.yimils.core.sys.po.UserRoleDo;
import com.yimils.core.sys.service.*;
import com.yimils.core.sys.vo.UserMenuVo;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


public class CustomRealm extends AuthorizingRealm {

    @Resource(name = "userService")
    private UserService userService;


    @Resource(name = "userRoleService")
    private UserRoleService userRoleService;

    @Resource(name = "roleService")
    private RoleService roleService;


    @Autowired
    private UserResourceUtil userResourceUtil;

    @Autowired
    private UserRoleVoBeanUtils userRoleVoBeanUtils;

    @Autowired
    private RoleVoBeanUtils roleVoBeanUtils;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        UserEntity userEntity = (UserEntity) principalCollection.getPrimaryPrincipal();

        Set<String> perms = roleVoBeanUtils.makePermissionsByUserId(userEntity.getId());
        if (perms.size() <= 0) {
            info.setRoles(new HashSet<>());
            info.setStringPermissions(new TreeSet<>());
            return info;
        }

        Set<String> roleSet = new HashSet<>();
        List<RoleEntity> entities = roleVoBeanUtils.getRolesByUserId(userEntity.getId());
        for (RoleEntity entity : entities) {
            roleSet.add(entity.getName());
        }

        info.setRoles(roleSet);
        info.setStringPermissions(perms);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("doGetAuthenticationInfo");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        UserEntity userEntity;
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserEntity::getName, username);
        userEntity = userService.getOne(wrapper);
        //not found
        if (userEntity == null) {
            throw new AuthenticationException();
        }
        //locked
        if (userEntity.getActive().equals(0)) {
            throw new AuthenticationException();
        }

        //构建左侧菜单
        UserMenuVo userMenuVo = new UserMenuVo();
        userEntity.setUserMenu(new UserMenuVo());
        if (roleVoBeanUtils.isAdminByUserId(userEntity.getId())) {
            userMenuVo.setMenuList(userResourceUtil.getMenuTree(null, false));
        } else {
            userMenuVo.setMenuList(userResourceUtil.getMenuTree(userEntity.getId(), false));
        }

        userEntity.setUserMenu(userMenuVo);

        //make permissions vo
        //get roles(多重角色)，用于登录后显示
        /*List<UserRoleDo> roles = userRoleService.getRolesByUserId(userEntity.getId());
        List<RoleEntity> entities = (List<RoleEntity>) roleService.listByIds(roles.stream().map(UserRoleDo::getRid)
                .collect(Collectors.toList()));*/
        QueryWrapper<UserRoleEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(UserRoleEntity::getUserId, userEntity.getId());
        List<UserRoleEntity> userRoles = userRoleService.list(qw);
        userEntity.setRoles(userRoleVoBeanUtils.cloneRecords(userRoles));
        List<RoleEntity> entities = (List<RoleEntity>) roleService.listByIds(userRoles.stream().map(UserRoleEntity::getRoleId)
                .collect(Collectors.toList()));
        //获取多重角色权限（并集）
        userEntity.setPermissions(roleVoBeanUtils.makePermissions(entities));
        return new SimpleAuthenticationInfo(userEntity, userEntity.getPassword(), ByteSource.Util.bytes(userEntity.getSalt()), getName());
    }

    /*private boolean isAdminByUserId(Long userId) {
        List<UserRoleDo> userRoleDos = roleMapper.getRolesByUserId(userId);
        for (UserRoleDo userRoleDo : userRoleDos) {
            return isAdminByRoleId(userRoleDo.getRid());
        }
        return false;
    }*/

    /*private boolean isAdminByRoleId(Long roleId) {
        if (roleId.equals(UserRoleDo.R_ADMIN)) {
            return true;
        }
        return false;
    }*/

    /*private boolean isAdminByRoles(List<RoleEntity> roles) {
        for (RoleEntity role : roles) {
            if (role.getId().equals(UserRoleDo.R_ADMIN)) {
                return true;
            }
        }
        return false;
    }*/

    /*private Set<String> makePermissions(List<RoleEntity> roles) {
        if (isAdminByRoles(roles)) {
            return getAllPermissions();
        } else {
            return getPermissionsByRoleId(roles);
        }
    }*/

    /*private Set<String> getAllPermissions() {
        List<ResourceEntity> dirs = resourceService.getDirAll();
        return makeResourceSetByDirs(dirs, null);
    }*/

    /*private Set<String> getPermissionsByRoleId(List<RoleEntity> roles) {
        Set<String> resourceSet = new TreeSet<>();
        for (RoleEntity role : roles) {
            List<ResourceEntity> dirs = resourceService.getDirByRoleId(role.getId());
            resourceSet.addAll(makeResourceSetByDirs(dirs, role.getId()));
        }
        return resourceSet;
    }*/

    /*private Set<String> makeResourceSetByDirs(List<ResourceEntity> dirs, Long roleId) {
        Set<String> resourceSet = new TreeSet<>();
        for (ResourceEntity dir : dirs) {
            List<ResourceEntity> menus;
            if (roleId == null) {
                menus = resourceService.getMenuAll(dir.getId());
            } else {
                menus = resourceService.getMenuByRoleId(dir.getId(), roleId);
            }
            for (ResourceEntity menu : menus) {
                List<ResourceEntity> perms;
                if (roleId == null) {
                    perms = resourceService.getPermAll(menu.getId());
                } else {
                    perms = resourceService.getPermByRoleId(menu.getId(),roleId);
                }
                for (ResourceEntity perm : perms) {
                    resourceSet.add(dir.getName() + ":" + menu.getName() + ":" + perm.getOpt());
                }
            }
        }
        return resourceSet;
    }*/
}
